package xyz.lwm.lazycat.jdkhttp;

import com.sun.net.httpserver.HttpExchange;
import xyz.lwm.lazycat.utility.IoUtil;
import xyz.lwm.lazycat.utility.It;
import xyz.lwm.lazycat.utility.StringUtil;
import xyz.lwm.lazycat.utility.exception.IoRuntimeException;
import xyz.lwm.lazycat.web.handle.ContentType;
import xyz.lwm.lazycat.web.handle.Header;
import xyz.lwm.lazycat.web.handle.HttpResponse;
import xyz.lwm.lazycat.web.handle.HttpStatus;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.charset.Charset;
import java.util.List;
import java.util.Map;

/**
 * 参考 hutool
 */
class JdkHttpResponse implements HttpResponse {

    private final HttpExchange httpExchange;

    private Charset charset;
    /**
     * 是否已经发送了Http状态码，如果没有，提前写出状态码
     */
    private boolean isSendCode;

    JdkHttpResponse(HttpExchange httpExchange) {
        this.httpExchange = httpExchange;
    }

    @Override
    public void setStatus(int httpStatusCode) {
        setStatus(httpStatusCode, 0);
    }

    @Override
    public void setStatus(int httpStatusCode, long bodyLength) {
        if (this.isSendCode) {
            throw new IoRuntimeException("Http status code has been send!");
        }

        try {
            this.httpExchange.sendResponseHeaders(httpStatusCode, bodyLength);
        } catch (IOException e) {
            throw new IoRuntimeException(e);
        }

        this.isSendCode = true;
    }

    @Override
    public boolean hasSetStatus() {
        return isSendCode;
    }

    @Override
    public Map<String, List<String>> getHeaders() {
        return httpExchange.getResponseHeaders();
    }

    @Override
    public void addHeader(String header, String value) {
        httpExchange.getResponseHeaders().add(header, value);
    }

    @Override
    public void setHeader(String header, String value) {
        httpExchange.getResponseHeaders().set(header, value);
    }

    @Override
    public void setHeader(Header header, String value) {
        httpExchange.getResponseHeaders().set(header.getValue(), value);
    }

    @Override
    public void setHeaders(Map<String, List<String>> headers) {
        getHeaders().putAll(headers);
    }

    @Override
    public void setContentType(String contentType) {
        if (null != contentType && null != this.charset) {
            if (!contentType.contains(";charset=")) {
                contentType = ContentType.build(contentType, this.charset);
            }
        }
        setHeader(Header.CONTENT_TYPE, contentType);
    }

    @Override
    public void setContentLength(long contentLength) {
        setHeader(Header.CONTENT_LENGTH, String.valueOf(contentLength));
    }

    @Override
    public void setCharset(Charset charset) {
        this.charset = charset;
    }

    @Override
    public void setAttr(String key, String value) {
        httpExchange.setAttribute(key, value);
    }

    @Override
    public OutputStream getOut() {
        return httpExchange.getResponseBody();
    }

    @Override
    public void write(String data) {
        Charset charset = It.of(this.charset).getOr(Charset.defaultCharset());
        if (StringUtil.isNotBlank(data)) {
            write(data.getBytes(charset));
        }
    }

    @Override
    public void write(byte[] data) {
        final ByteArrayInputStream in = new ByteArrayInputStream(data);
        write(in, in.available());
    }

    @Override
    public void write(InputStream in) {
        write(in, 0);
    }

    // base method, 不关闭输入输出流, 后续会自动关闭的
    @Override
    public void write(InputStream in, int length) {
        if (!isSendCode) {
            setStatus(HttpStatus.HTTP_OK, Math.max(0, length));
        }

        OutputStream out = this.httpExchange.getResponseBody();
        IoUtil.copy(in, out, false);
    }

    @Override
    public void write(InputStream in, int length, String contentType, String fileName) {
        Charset charset = It.of(this.charset).getOr(Charset.defaultCharset());
        if (!contentType.startsWith("text/")) {
            // 非文本类型数据直接走下载
            String str = StringUtil.format("attachment;filename={}",
                    JdkParamUtil.encode(fileName, charset));
            setHeader(Header.CONTENT_DISPOSITION, str);
        }
        write(in, length);
    }
}
